/*
 * Copyright 2012 The Netty Project
 *
 * The Netty Project licenses this file to you under the Apache License,
 * version 2.0 (the "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at:
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations
 * under the License.
 */
package com.creditease.shield.flow.handler;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;

import org.apache.commons.lang3.tuple.Pair;

import com.creditease.shield.flow.common.msg.Request;
import com.creditease.shield.flow.common.msg.Response;

import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;

/**
 * Handler implementation for the object echo client. It initiates the ping-pong
 * traffic between the object echo client and server by sending the first
 * message to the server.
 */
@Sharable
public class FlowNoClientHandler extends SimpleChannelInboundHandler<Response> {

	// 用blocking queue主要是用阻塞的功能，省的自己加锁
	private final ConcurrentHashMap<String, BlockingQueue<Response>> responseMap = new ConcurrentHashMap<String, BlockingQueue<Response>>();

	@Override
	protected void channelRead0(ChannelHandlerContext ctx, Response msg) throws Exception {
		System.out.println("receive response:" + msg);
		BlockingQueue<Response> queue = responseMap.get(msg.getTraceId());
		// 高并发下可能为null
		if (queue == null) {
			queue = new LinkedBlockingQueue<Response>(1);
			responseMap.putIfAbsent(msg.getTraceId(), queue);
		}
		queue.add(msg);

	}

	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
		super.exceptionCaught(ctx, cause);
		cause.printStackTrace();
	}

	public Response send(Request request, Pair<Long, TimeUnit> timeout) throws InterruptedException {
		responseMap.putIfAbsent(request.getTraceId(), new LinkedBlockingQueue<Response>(1));
		Response response = null;
		try {
			BlockingQueue<Response> queue = responseMap.get(request.getTraceId());
			if (timeout == null) {
				response = queue.take();
			} else {
				response = queue.poll(timeout.getKey(), timeout.getValue());
			}
		} finally {
			responseMap.remove(request.getTraceId());
		}
		return response;
	}

}
